﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using System.Xml.Linq;
//
using PerceptiveMCAPI.Types.Internal;

namespace PerceptiveMCAPI.Types
{
	public class getAccountDetailsOutput : Api_BaseOutput
	{
		public getAccountDetailsResults result { get; set; }
		public getAccountDetailsParms inputParms { get; private set; }
		//
		public getAccountDetailsOutput( getAccountDetailsInput input )
			: base( input )
		{
			this.inputParms = input.parms;
			this.result = new getAccountDetailsResults();
		}
		// --------------------------------------------------- tostring
		public override string ToString()
		{
			return string.Format( "{0}", result.username );
		}

		#region ================================================================== format setup

		// ---- serial
		internal void Format( string api_Request, string api_Response )
		{
			this.api_Request = api_Request;
			this.api_Response = api_Response;
			// ----------------------------------
			if ( this.api_OutputType == EnumValues.OutputType.JSON )
				outputJSON();
			else if ( this.api_OutputType == EnumValues.OutputType.XML )
				outputXML();
		}
		// ---- xmlrpc
		internal void Format( x_getAccountDetails rpcResult )
		{
			this.api_Request = EnumValues.NotSupplied;
			this.api_Response = EnumValues.NotSupplied;
			// ------------------------
			this.result = FormatResults( rpcResult );
		}

		#endregion

		#region ================================================================= Output

		// ---------------------------------------------------------- outputJSON
		protected void outputJSON()
		{
			JavaScriptSerializer jss = new JavaScriptSerializer();

			try
			{
				if ( this.api_Response.Contains( EnumValues.JSONErrorString ) )
				{
					Api_Error err = jss.Deserialize<Api_Error>( this.api_Response );
					this.api_ErrorMessages.Add( err );
				}
				else
				{
					Hashtable jsonHash = jss.Deserialize<Hashtable>( this.api_Response );
					x_getAccountDetails jsonResult = FormatHashToXfile( jsonHash );
					this.result = FormatResults( jsonResult );
				}
			}
			catch ( Exception ex )
			{
				this.api_ErrorMessages.Add( apiException.FormatError( ex ) );
			}
		}

		private x_getAccountDetails FormatHashToXfile( Hashtable jsonHash )
		{
			x_getAccountDetails wrk = new x_getAccountDetails();
			//
			IDictionaryEnumerator ide = jsonHash.GetEnumerator();
			while ( ide.MoveNext() )
			{
				if ( ide.Entry.Key.ToString() == "user_id" ) wrk.user_id = ide.Entry.Value.ToString() ?? "";
				if ( ide.Entry.Key.ToString() == "username" ) wrk.username = ide.Entry.Value.ToString() ?? "";
				if ( ide.Entry.Key.ToString() == "member_since" ) wrk.member_since = ide.Entry.Value.ToString() ?? "";
				if ( ide.Entry.Key.ToString() == "is_approved" ) wrk.is_approved = (bool)ide.Entry.Value;
				if ( ide.Entry.Key.ToString() == "is_trial" ) wrk.is_trial = (bool)ide.Entry.Value;
				if ( ide.Entry.Key.ToString() == "timezone" ) wrk.timezone = ide.Entry.Value.ToString() ?? "";
				if ( ide.Entry.Key.ToString() == "plan_type" ) wrk.plan_type = ide.Entry.Value.ToString() ?? "";
				if ( ide.Entry.Key.ToString() == "plan_low" ) wrk.plan_low = (int)ide.Entry.Value;
				if ( ide.Entry.Key.ToString() == "plan_high" ) wrk.plan_high = (int)ide.Entry.Value;
				if ( ide.Entry.Key.ToString() == "plan_start_date" ) wrk.plan_start_date = ide.Entry.Value.ToString() ?? "";
				if ( ide.Entry.Key.ToString() == "emails_left" ) wrk.emails_left = (int)ide.Entry.Value;
				if ( ide.Entry.Key.ToString() == "pending_monthly" ) wrk.pending_monthly = (bool)ide.Entry.Value;
				if ( ide.Entry.Key.ToString() == "first_payment" ) wrk.first_payment = string.Format( "{0}", ide.Entry.Value );
				if ( ide.Entry.Key.ToString() == "last_payment" ) wrk.last_payment = string.Format( "{0}", ide.Entry.Value );
				if ( ide.Entry.Key.ToString() == "times_logged_in" ) wrk.times_logged_in = (int)ide.Entry.Value;
				if ( ide.Entry.Key.ToString() == "last_login" ) wrk.last_login = ide.Entry.Value.ToString() ?? "";
				if ( ide.Entry.Key.ToString() == "affiliate_link" ) wrk.affiliate_link = ide.Entry.Value.ToString() ?? "";
				if ( ide.Entry.Key.ToString() == "contact" ) wrk.contact = ide.Entry.Value;
				if ( ide.Entry.Key.ToString() == "modules" ) wrk.modules = ide.Entry.Value;
				if ( ide.Entry.Key.ToString() == "orders" ) wrk.orders = ide.Entry.Value;
				if ( ide.Entry.Key.ToString() == "rewards" ) wrk.rewards = ide.Entry.Value;
			}
			return wrk;
		}
		// ---------------------------------------------------------- outputXML
		protected void outputXML()
		{
			XElement xml = XElement.Parse( this.api_Response );
			// error check
			Api_Error error = apiSerial.GetXmlOutputError( xml );
			if ( error != null )
			{
				this.api_ErrorMessages.Add( error );
				return;
			}
			// -------------------------------------------- get values
			try
			{
				DateTime dt; int it; double dbl; float fl = 0;
				getAccountDetailsResults acct = new getAccountDetailsResults();
				XElement root = xml;
				//
				acct.user_id = root.Element( "user_id" ).Value;
				acct.username = root.Element( "username" ).Value;
				DateTime.TryParse( root.Element( "member_since" ).Value, out dt );
				acct.member_since = dt;
				acct.is_approved = ( root.Element( "is_approved" ).Value.Trim() == "1" ) ? true : false;
				acct.is_trial = ( root.Element( "is_trial" ).Value.Trim() == "1" ) ? true : false;
				acct.timezone = root.Element( "timezone" ).Value;
				acct.plan_type = root.Element( "plan_type" ).Value;
				int.TryParse( root.Element( "emails_left" ).Value, out it );
				acct.emails_left = it;
				acct.pending_monthly = ( root.Element( "pending_monthly" ).Value.Trim() == "1" ) ? true : false;
				DateTime.TryParse( root.Element( "first_payment" ).Value, out dt );
				acct.first_payment = dt;
				DateTime.TryParse( root.Element( "last_payment" ).Value, out dt );
				acct.last_payment = dt;
				int.TryParse( root.Element( "times_logged_in" ).Value, out it );
				acct.times_logged_in = it;
				DateTime.TryParse( root.Element( "last_login" ).Value, out dt );
				acct.last_login = dt;
				acct.affiliate_link = root.Element( "affiliate_link" ).Value;
				// contact
				XElement ctcInfo = root.Element( "contact" );
				acct.contact.fname = ctcInfo.Element( "fname" ).Value ?? "";
				acct.contact.lname = ctcInfo.Element( "lname" ).Value ?? "";
				acct.contact.company = ctcInfo.Element( "company" ).Value ?? "";
				acct.contact.address1 = ctcInfo.Element( "address1" ).Value ?? "";
				acct.contact.address2 = ctcInfo.Element( "address2" ).Value ?? "";
				acct.contact.city = ctcInfo.Element( "city" ).Value ?? "";
				acct.contact.state = ctcInfo.Element( "state" ).Value ?? "";
				acct.contact.zip = ctcInfo.Element( "zip" ).Value ?? "";
				acct.contact.country = ctcInfo.Element( "country" ).Value ?? "";
				acct.contact.email = ctcInfo.Element( "email" ).Value ?? "";
				acct.contact.url = ctcInfo.Element( "url" ).Value ?? "";
				acct.contact.phone = ctcInfo.Element( "phone" ).Value ?? "";
				acct.contact.fax = ctcInfo.Element( "fax" ).Value ?? "";
				// -- modules
				XElement moduleArray = root.Element( "modules" );
				if ( moduleArray.HasElements )
				{
					IEnumerable<XElement> modules = moduleArray.Elements( "struct" );
					foreach ( XElement module in modules )
					{
						string name = module.Element( "name" ).Value;
						DateTime.TryParse( module.Element( "added" ).Value, out dt );
						acct.modules.Add( new getAccountDetails_module { name = name, added = dt } );
					}
				}
				// orders
				XElement orderArray = root.Element( "orders" );
				if ( orderArray.HasElements )
				{
					IEnumerable<XElement> orders = orderArray.Elements( "struct" );
					foreach ( XElement order in orders )
					{
						getAccountDetails_order ord = new getAccountDetails_order();

						int.TryParse( order.Element( "order_id" ).Value, out it );
						ord.order_id = it;

						ord.type = order.Element( "type" ).Value ?? "";

						if ( !order.Element( "amount" ).IsEmpty )
						{
							float.TryParse( order.Element( "amount" ).Value, out fl );
							ord.amount = fl;
						}
						if ( !order.Element( "date" ).IsEmpty )
						{
							DateTime.TryParse( order.Element( "date" ).Value, out dt );
							ord.order_date = dt;
						}
						else
						{ ord.order_date = DateTime.MinValue; }

						if ( !order.Element( "credits_used" ).IsEmpty )
						{
							float.TryParse( order.Element( "credits_used" ).Value, out fl );
							ord.credits_used = fl;
						}
						//
						acct.orders.Add( ord );
					}
				}
				// rewards
				XElement rewardsArray = root.Element( "rewards" );
				if ( rewardsArray.HasElements )
				{
					int.TryParse( rewardsArray.Element( "referrals_this_month" ).Value, out it );
					acct.rewards.referrals_this_month = it;
					acct.rewards.notify_on = ( rewardsArray.Element( "notify_on" ).Value.Trim() == "1" ) ? true : false;
					acct.rewards.notify_email = rewardsArray.Element( "notify_email" ).Value ?? "";
					// credits
					if ( rewardsArray.Element( "credits" ).HasElements )
					{
						XElement credits_array = rewardsArray.Element( "credits" );
						double.TryParse( credits_array.Element( "this_month" ).Value, out dbl );
						acct.rewards.credits.this_month = dbl;
						double.TryParse( credits_array.Element( "total_earned" ).Value, out dbl );
						acct.rewards.credits.total_earned = dbl;
						double.TryParse( credits_array.Element( "remaining" ).Value, out dbl );
						acct.rewards.credits.remaining = dbl;
					}
					// inspections
					if ( rewardsArray.Element( "inspections" ).HasElements )
					{
						XElement inspect_array = rewardsArray.Element( "inspections" );
						double.TryParse( inspect_array.Element( "this_month" ).Value, out dbl );
						acct.rewards.inspections.this_month = dbl;
						double.TryParse( inspect_array.Element( "total_earned" ).Value, out dbl );
						acct.rewards.inspections.total_earned = dbl;
						double.TryParse( inspect_array.Element( "remaining" ).Value, out dbl );
						acct.rewards.inspections.remaining = dbl;
					}
					// referrals
					if ( rewardsArray.Element( "referrals" ).HasElements )
					{
						IEnumerable<XElement> referrals_array = rewardsArray.Element( "referrals" ).Descendants( "struct" );

						foreach ( XElement refer_struct in referrals_array )
						{
							getAccountDetails_rewards.reward_referral referral = new getAccountDetails_rewards.reward_referral();
							referral.name = refer_struct.Element( "name" ).Value ?? "";
							referral.email = refer_struct.Element( "email" ).Value ?? "";
							DateTime.TryParse( refer_struct.Element( "signup_date" ).Value, out dt );
							referral.signup_date = dt;
							referral.type = refer_struct.Element( "type" ).Value ?? "";
							acct.rewards.referrals.Add( referral );
						}
					}
					// applied
					if ( rewardsArray.Element( "applied" ).HasElements )
					{
						IEnumerable<XElement> applied_array = rewardsArray.Element( "applied" ).Descendants( "struct" );

						foreach ( XElement applied_struct in applied_array )
						{
							getAccountDetails_rewards.reward_applied applied = new getAccountDetails_rewards.reward_applied();
							//
							double.TryParse( applied_struct.Element( "value" ).Value, out dbl );
							applied.value = dbl;
							DateTime.TryParse( applied_struct.Element( "date" ).Value, out dt );
							applied.date = dt;
							int.TryParse( applied_struct.Element( "order_id" ).Value, out it );
							applied.order_id = it;
							applied.order_desc = applied_struct.Element( "order_desc" ).Value ?? "";
							acct.rewards.applied.Add( applied );
						}
					}
				}
				// ----------------------
				this.result = acct;
			}
			catch ( Exception ex )
			{
				this.api_ErrorMessages.Add( apiException.FormatError( ex ) );
			}
		}

		// ---------------------------------------------------------- Formatting
		private getAccountDetailsResults FormatResults( x_getAccountDetails x_results )
		{
			DateTime dt;
			getAccountDetailsResults result = new getAccountDetailsResults();
			result.user_id = x_results.user_id;
			result.username = x_results.username;
			DateTime.TryParse( x_results.member_since, out dt );
			result.member_since = dt;
			result.is_approved = x_results.is_approved;
			result.is_trial = x_results.is_trial;
			result.timezone = x_results.timezone;
			result.plan_type = x_results.plan_type;
			result.plan_low = x_results.plan_low;
			result.plan_high = x_results.plan_high;
			DateTime.TryParse( x_results.plan_start_date, out dt );
			result.plan_start_date = dt;
			result.emails_left = x_results.emails_left;
			result.pending_monthly = x_results.pending_monthly;
			DateTime.TryParse( x_results.first_payment, out dt );
			result.first_payment = dt;
			DateTime.TryParse( x_results.last_payment, out dt );
			result.last_payment = dt;
			result.times_logged_in = x_results.times_logged_in;
			DateTime.TryParse( x_results.last_login, out dt );
			result.last_login = dt;
			result.affiliate_link = x_results.affiliate_link;
			// ----------------------------------------------------- contact, modules, orders , rewards
			result.contact = FormatContact( x_results.contact );
			result.modules = FormatModules( x_results.modules );
			result.orders = FormatOrders( x_results.orders );
			result.rewards = FormatRewards( x_results.rewards );

			return result;
		}

		private getAccountDetails_contact FormatContact( object contact_struct )
		{
			getAccountDetails_contact contact = new getAccountDetails_contact();
			IDictionary ctc = contact_struct as IDictionary;
			// ---------------
			// contact info
			// ---------------
			contact.fname = ( ctc["fname"] == null ) ? "" : ctc["fname"].ToString();
			contact.lname = ( ctc["lname"] == null ) ? "" : ctc["lname"].ToString();
			contact.email = ( ctc["email"] == null ) ? "" : ctc["email"].ToString();
			contact.company = ( ctc["company"] == null ) ? "" : ctc["company"].ToString();
			contact.address1 = ( ctc["address1"] == null ) ? "" : ctc["address1"].ToString();
			contact.address2 = ( ctc["address2"] == null ) ? "" : ctc["address2"].ToString();
			contact.city = ( ctc["city"] == null ) ? "" : ctc["city"].ToString();
			contact.state = ( ctc["state"] == null ) ? "" : ctc["state"].ToString();
			contact.zip = ( ctc["zip"] == null ) ? "" : ctc["zip"].ToString();
			contact.country = ( ctc["country"] == null ) ? "" : ctc["country"].ToString();
			contact.url = ( ctc["url"] == null ) ? "" : ctc["url"].ToString();
			contact.phone = ( ctc["phone"] == null ) ? "" : ctc["phone"].ToString();
			contact.fax = ( ctc["fax"] == null ) ? "" : ctc["fax"].ToString();
			//
			return contact;
		}

		private List<getAccountDetails_module> FormatModules( object modulesObject )
		{
			DateTime dt;
			List<getAccountDetails_module> modules = new List<getAccountDetails_module>();
			object[] modulesArray = modulesObject as object[];

			foreach ( object obj in modulesArray )
			{
				getAccountDetails_module acctModule = new getAccountDetails_module();
				IDictionary mod = obj as IDictionary;
				acctModule.name = mod["name"].ToString();
				DateTime.TryParse( mod["added"].ToString(), out dt );
				acctModule.added = dt;
				//
				modules.Add( acctModule );
			}
			return modules;
		}

		private List<getAccountDetails_order> FormatOrders( object ordersObject )
		{
			int it; DateTime dt; float fl;
			List<getAccountDetails_order> orders = new List<getAccountDetails_order>();
			object[] ordersArray = ordersObject as object[];

			foreach ( object obj in ordersArray )
			{
				getAccountDetails_order acctOrder = new getAccountDetails_order();
				IDictionary ord = obj as IDictionary;
				//----------------------------------------------------------------
				int.TryParse( ord["order_id"].ToString(), out it );
				acctOrder.order_id = it;
				acctOrder.type = ord["type"].ToString();
				if ( apiHelper.IsNumeric( ord["amount"].ToString() ) )
				{
					float.TryParse( ord["amount"].ToString(), out fl );
					acctOrder.amount = fl;
				}
				if ( ord["date"] != null )
				{
					DateTime.TryParse( ord["date"].ToString(), out dt );
					acctOrder.order_date = dt;
				}
				if ( ord["credits_used"] != null )
				{
					float.TryParse( ord["credits_used"].ToString(), out fl );
					acctOrder.credits_used = fl;
				}

				orders.Add( acctOrder );
			}
			return orders;
		}

		private getAccountDetails_rewards FormatRewards( object rewardsObject )
		{
			int it; bool bt;
			getAccountDetails_rewards rewards = new getAccountDetails_rewards();

			//--------------------------------------------------------
			IDictionary reward = rewardsObject as IDictionary;
			if ( reward["referrals_this_month"] != null )
			{
				int.TryParse( reward["referrals_this_month"].ToString(), out it );
				rewards.referrals_this_month = it;
			}
			if ( reward["notify_on"] != null )
			{
				bool.TryParse( reward["notify_on"].ToString(), out bt );
				rewards.notify_on = bt;
			}
			if ( reward["notify_email"] != null )
				rewards.notify_email = reward["notify_email"].ToString() ?? string.Empty;

			if ( reward["credits"] != null )
			{
				IDictionary reward_credits = reward["credits"] as IDictionary;
				rewards.credits = getCredits( reward_credits );
			}

			if ( reward["inspections"] != null )
			{
				IDictionary reward_inspect = reward["inspections"] as IDictionary;
				rewards.inspections = getInspections( reward_inspect );
			}

			if ( reward["referrals"] != null )
			{
				object[] reward_referrals = reward["referrals"] as object[];
				rewards.referrals = getReferrals( reward_referrals );
			}

			if ( reward["applied"] != null )
			{
				object[] reward_applied = reward["applied"] as object[];
				rewards.applied = getApplied( reward_applied );
			}

			return rewards;
		}

		private getAccountDetails_rewards.reward_credits getCredits( IDictionary credit_struct )
		{
			double dbl;
			getAccountDetails_rewards.reward_credits credits = new getAccountDetails_rewards.reward_credits();

			double.TryParse( credit_struct["this_month"].ToString(), out dbl );
			credits.this_month = dbl;
			double.TryParse( credit_struct["total_earned"].ToString(), out dbl );
			credits.total_earned = dbl;
			double.TryParse( credit_struct["remaining"].ToString(), out dbl );
			credits.remaining = dbl;
			//
			return credits;
		}

		private getAccountDetails_rewards.reward_inspections getInspections( IDictionary inspect_struct )
		{
			double dbl;
			getAccountDetails_rewards.reward_inspections inspects = new getAccountDetails_rewards.reward_inspections();
			double.TryParse( inspect_struct["this_month"].ToString(), out dbl );
			inspects.this_month = dbl;
			double.TryParse( inspect_struct["total_earned"].ToString(), out dbl );
			inspects.total_earned = dbl;
			double.TryParse( inspect_struct["remaining"].ToString(), out dbl );
			inspects.remaining = dbl;
			//
			return inspects;
		}

		private List<getAccountDetails_rewards.reward_referral> getReferrals( object[] referrals_struct )
		{
			DateTime dt;
			List<getAccountDetails_rewards.reward_referral> referrals = new List<getAccountDetails_rewards.reward_referral>();
			foreach ( object referral_obj in referrals_struct )
			{
				getAccountDetails_rewards.reward_referral referral = new getAccountDetails_rewards.reward_referral();
				IDictionary dict = referral_obj as IDictionary;
				if ( dict["name"] != null )
					referral.name = dict["name"].ToString();
				if ( dict["email"] != null )
					referral.email = dict["email"].ToString();
				if ( dict["signup_date"] != null )
				{
					DateTime.TryParse( dict["signup_date"].ToString(), out dt );
					referral.signup_date = dt;
				}
				if ( dict["type"] != null )
					referral.type = dict["type"].ToString();
				//
				referrals.Add( referral );
			}
			//
			return referrals;
		}

		private List<getAccountDetails_rewards.reward_applied> getApplied( object[] applied_struct )
		{
			// DateTime dt;
			List<getAccountDetails_rewards.reward_applied> applieds = new List<getAccountDetails_rewards.reward_applied>();
			foreach ( object applied_obj in applied_struct )
			{
				getAccountDetails_rewards.reward_applied applied = new getAccountDetails_rewards.reward_applied();
				IDictionary dict = applied_obj as IDictionary;
				//
				// TODO: get structure and implement
				//
				// applieds.Add( applied );
			}
			//
			return applieds;
		}

		#endregion
	}
}
